
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate serde_derive;
extern crate web_view;
extern crate serde_json;
extern crate threadpool;
extern crate base64;
extern crate crossbeam;
extern crate crossbeam_channel;

use chrono::Local;
use colog;
use std::io::Write;
pub mod view;
// use view::UI;
#[macro_use]
pub mod widgets;
pub mod action;
// pub mod net;
pub mod proxy;
pub mod utils;

#[allow(unused_imports)]
// use view::SP2;

pub trait SP2 {
    fn split_twice(&self, sep: &str) -> (String, String, String);
    fn split_once(&self, sep: &str) -> (String, String);
}

impl SP2 for String {
    fn split_twice(&self, sep: &str) -> (String, String, String) {
        let mut f = self.split(sep);
        (
            f.next().unwrap().to_string(),
            f.next().unwrap().to_string(),
            f.next().unwrap().to_string(),
        )
    }
    fn split_once(&self, sep: &str) -> (String, String) {
        let mut f = self.split(sep);
        (f.next().unwrap().to_string(), f.next().unwrap().to_string())
    }
}

impl<'a> SP2 for &'a str {
    fn split_twice(&self, sep: &str) -> (String, String, String) {
        let mut f = self.split(sep);
        (
            f.next().unwrap().to_string(),
            f.next().unwrap().to_string(),
            f.next().unwrap().to_string(),
        )
    }
    fn split_once(&self, sep: &str) -> (String, String) {
        let mut f = self.split(sep);
        (f.next().unwrap().to_string(), f.next().unwrap().to_string())
    }
}


#[allow(dead_code)]
pub fn log_init() {
    let mut clog = colog::builder();
    clog.format(|buf, record| {
        writeln!(
            buf,
            "{} [{}] - {}",
            Local::now().format("%Y-%m-%dT%H:%M:%S"),
            record.level(),
            record.args()
        )
    });
    // clog.filter(None, log::LevelFilter::Warn);
    clog.init();
}

pub fn with_search_extend<'a, F>(html: &view::UI, how_handle: F)
where
    F: Fn(view::S<String>, view::R<String>) + Send + 'static,
{
    search_box(how_handle, html);
}

pub fn app_with<'a, F>(html: &view::UI, res_files:Vec<&str>, how_handle: F)
where
    F: Fn(view::S<String>, view::R<String>) + Send + 'static,
{
    let _ = view::with_build_web(html, res_files,  how_handle);
}


pub fn with_search<'a, F>(how_handle: F)
where
    F: Fn(view::S<String>, view::R<String>) + Send + 'static,
{
    let html = view::UI::default();
    search_box(how_handle, &html);
}


pub fn rpc_from(rx: view::R<String>, tx: view::S<String>) -> (String, String, String) {
    if let Some(m) = view::Brd::recv_with(rx, tx, view::TO_HANDLER) {
        m.split_twice(view::MSG_SEP)
    } else {
        ("".to_string(), "".to_string(), "".to_string())
    }
}

pub fn rpc_from_id(rx: view::R<String>, tx: view::S<String>, id: &str) -> (String, String, String) {
    if let Some(m) = view::Brd::recv_with(rx, tx, &format!("{}{}", view::TO_HANDLER, id)) {
        m.split_twice(view::MSG_SEP)
    } else {
        ("".to_string(), "".to_string(), "".to_string())
    }
}

pub fn rpc_from_msg(msg: &str) -> (String, String, String) {
    msg.split_twice(view::MSG_SEP)
}

pub fn rpc_msg_progress(id: &str, tp: &str, content: &str, pro: usize) {
    let r = view::Rpc {
        id: id.to_string(),
        tp: tp.to_string(),
        progress: format!("{}", pro),
        content: vec![content.to_string()],
    };
    let c = serde_json::to_string(&r).expect("trans to json failed!");
    let c_json = base64::encode(c.as_bytes());
    // view::Brd::send_to(tx, view::TO_RENDER, &c_json);
    view::brd(view::TO_RENDER, &c_json);
    // tx.send(c_json).expect("send to view failed");
}

pub fn rpc_msg(id: &str, tp: &str, content: &str) {
    let r = view::Rpc {
        id: id.to_string(),
        tp: tp.to_string(),
        progress: "none".to_string(),
        content: vec![content.to_string()],
    };
    let c = serde_json::to_string(&r).expect("trans to json failed!");
    let c_json = base64::encode(c.as_bytes());
    // tx.send(c_json).expect("send to view failed");
    view::brd(view::TO_RENDER, &c_json);
    // view::Brd::send_to(tx, view::TO_RENDER, &c_json);
}

pub fn rpc_list_pro(id: &str, tp: &str, pro: usize, content: &Vec<String>) {
    let r = view::Rpc {
        id: id.to_string(),
        tp: tp.to_string(),
        progress: format!("{}", pro),
        content: content.clone(),
    };

    let c = serde_json::to_string(&r).expect("trans to json failed!");
    // tx.send(c).expect("send to view failed");
    let c_json = base64::encode(c.as_bytes());
    view::brd(view::TO_RENDER, &c_json);
    // view::Brd::send_to(tx, , &c);
}

pub fn rpc_list(id: &str, tp: &str, content: &Vec<String>) {
    let r = view::Rpc {
        id: id.to_string(),
        tp: tp.to_string(),
        progress: "none".to_string(),
        content: content.clone(),
    };

    let c = serde_json::to_string(&r).expect("trans to json failed!");
    // tx.send(c).expect("send to view failed");
    let c_json = base64::encode(c.as_bytes());
    view::brd(view::TO_RENDER, &c_json);
    // view::Brd::send_to(tx, view::TO_RENDER, &c);
}

pub trait B64 {
    fn b64(&self) -> Vec<String>;
}

impl B64 for Vec<String> {
    fn b64(&self) -> Vec<String> {
        self.iter().map(|s| base64::encode(s.as_bytes())).collect()
    }
}

#[allow(dead_code)]
pub fn to_rpc_msg(id: &str, msg: &str) -> String {
    view::Rpc::to_msg(id, "normal", msg)
}

fn search_box<'a, F>(how_handle: F, html: &view::UI)
where
    F: FnOnce(view::S<String>, view::R<String>) + Send + 'static,
{
    // log_inif();
    // view::job_with(how_handle);
    let _ = view::with_build(html, how_handle);
}


pub fn load_res_files(res:&str) -> Vec<&str>{
    res.trim().split("\n").filter(|x| x.trim().len() >0).map(|x| x.trim()).collect()
}

#[test]
fn test_macro() {

    // let mut h = with_html!{@li
    //     (I "hello"),
    //     (B "check it")
    //     @css
    //     button#check-it{
    //         position: absolute;
    //         bottom: 1%;
    //     }
    //     @js
    //     console.log("hello")

    // };
    // h.add_js("console.log('hllo');");
    // println!("html {}",h.html);
    // println!("css {}",h.css);
    // println!("js {}",h.js);
}

#[test]
fn file() {
    // use utils::FileSystem;
    // // let ffff:Box<dyn Fn(&str) -> bool> = "screen.png$".to_regex_filter();
    // // assert!(ffff("screen.png"), true);
    // let f = "screen.png$".re();
    // // assert!(f("screen.png") == true, true);
    // let fs =  "./".ein(f);
    // assert!(fs.len() == 2, true);
}
